package com.vision.sales.cm.db.data;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import net.sf.gilead.pojo.gwt.LightEntity;

import com.vision.core.cm.data.IHasSystemTime;
import com.vision.core.cm.db.data.Company;
import com.vision.sales.cm.data.DebitMemoType;
import com.vision.sales.cm.data.IHasSalesInvoice;
import com.vision.sales.cm.data.IHasTransactionStatus;
import com.vision.sales.cm.data.TransactionStatus;

/**
 * Represents a Debit Memo for a {@link Customer}. This is then applied to a {@link SalesInvoice}.
 * 
 * @author Mark
 *
 */
@Entity
@Table(name = DebitMemo.TABLE)
public class DebitMemo extends LightEntity implements Serializable, IHasSalesInvoice, IHasTransactionStatus, IHasSystemTime {
	
	public static interface FieldSpecs {
		int DM_NO_MAX = 20;
		int REMARKS_MAX = 300;
	}

	private static final long serialVersionUID = 5586067613565544061L;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public static final String TABLE = "debit_memo";
	
	public static final String COL_ID = "id";
	public static final String COL_COMPANY_ID = "company_id";
	public static final String COL_NO = "debit_memo_no";
	public static final String COL_DATE = "date";
	public static final String COL_TYPE = "type";
	public static final String COL_AMOUNT = "amount";
	public static final String COL_CUSTOMER_ID = "customer_id";
	public static final String COL_SALES_INVOICE_ID = "invoice_id";
	public static final String COL_REMARKS = "remarks";
	public static final String COL_STATUS = "status";
	
	public static final String COL_SYS_CREATED = "sys_created";
	public static final String COL_SYS_LAST_MOD = "sys_last_mod";
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "sdebit_memo")
	@SequenceGenerator(name = "sdebit_memo", sequenceName = "debit_memo_seq")
	@Column(name = "id")
	private Long id;
	
	/**
	 * The {@link Company}.
	 */
	@ManyToOne
	@JoinColumn(name = COL_COMPANY_ID, nullable = false)
	private Company company;
	
	/**
	 * The {@link DebitMemo}'s number.
	 */
	@Column(name = COL_NO, nullable = false, unique = true, length = FieldSpecs.DM_NO_MAX)
	private String debitMemoNo;
	
	/**
	 * The {@link DebitMemo}'s date.
	 */
	@Column(name = COL_DATE, nullable = false)
	@Temporal(TemporalType.DATE)
	private Date date;
	
	/**
	 * The type of the {@link DebitMemo}.
	 */
	@Column(name = COL_TYPE, nullable = false)
	@Enumerated(EnumType.STRING)
	private DebitMemoType type;
	
	/**
	 * The amount to be applied.
	 */
	@Column(name = COL_AMOUNT, nullable = false)
	private double amount;
	
	/**
	 * The {@link Customer}
	 */
	@ManyToOne
	@JoinColumn(name = COL_CUSTOMER_ID, nullable = false)
	private Customer customer;
	
	/**
	 * The {@link SalesInvoice} to which the {@link DebitMemo} was applied.
	 */
	@ManyToOne
	@JoinColumn(name = COL_SALES_INVOICE_ID, nullable = false)
	private SalesInvoice salesInvoice;

	/**
	 * User remarks.
	 */
	@Column(name = COL_REMARKS, nullable = true, length = FieldSpecs.REMARKS_MAX)
	private String remarks;

	@Column(name = COL_STATUS, nullable = false)
	@Enumerated(EnumType.STRING)
	private TransactionStatus status;
	
	// For internal use %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	/**
	 * The server {@link Timestamp} this object was created.
	 */
	@Column(name = COL_SYS_CREATED, nullable = false)
	private Timestamp sysCreated;
	
	/**
	 * The server {@link Timestamp} this object was last modified.
	 */
	@Column(name = COL_SYS_LAST_MOD, nullable = false)
	private Timestamp sysLastModified;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	public DebitMemo() { }
	
	public DebitMemo(Date date) {
		this.date = date;
	}
	
	@Override
	public boolean equals(Object object) {
		if (object instanceof Collection) {
			DebitMemo o = (DebitMemo) object;
			return id.equals(o.id);
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return id == null ? super.hashCode() : id.hashCode();
	}
	
	@Override
	public String toString() {
		return id + ": " + debitMemoNo + "(" + date + ")" + ":" + type;
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	public Company getCompany() {
		return company;
	}

	public void setCompany(Company company) {
		this.company = company;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getDebitMemoNo() {
		return debitMemoNo;
	}

	public void setDebitMemoNo(String debitMemoNo) {
		this.debitMemoNo = debitMemoNo;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public DebitMemoType getType() {
		return type;
	}

	public void setType(DebitMemoType type) {
		this.type = type;
	}

	public double getAmount() {
		return amount;
	}

	public void setAmount(double amount) {
		this.amount = amount;
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public SalesInvoice getSalesInvoice() {
		return salesInvoice;
	}

	public void setSalesInvoice(SalesInvoice salesInvoice) {
		this.salesInvoice = salesInvoice;
	}

	public String getRemarks() {
		return remarks;
	}

	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}
	
	public TransactionStatus getStatus() {
		return status;
	}
	
	public void setStatus(TransactionStatus status) {
		this.status = status;
	}

	public Timestamp getSysCreated() {
		return sysCreated;
	}

	public void setSysCreated(Timestamp sysCreated) {
		this.sysCreated = sysCreated;
	}

	public Timestamp getSysLastModified() {
		return sysLastModified;
	}

	public void setSysLastModified(Timestamp sysLastModified) {
		this.sysLastModified = sysLastModified;
	}

}
